/// \file
#ifndef FILE_filesystemdata_H
#define FILE_filesystemdata_H

#include "hdi.h"

#define PARTITIONFORMATSTRINGLEN 8
#define FILESYSTEMVERSION 1

#define FSDBLOCK 0
#define FSBYTEMAPBLOCK 1

#define FSBITMAP_BLOCKINFOPERBLOCK(fsd) ((((fsd).blockSize-sizeof(blockid_t))*4))

#if FSDBLOCK >= FSBYTEMAPBLOCK || FSROOTBLOCK >= FSBYTEMAPBLOCK
	#error "The blocks are not in correct locations."
#endif

/// Contains the metadata of the partition/disk.
///
/// This struct is written to the 1rst block (blockid 0) of the partition.
/// The MBR won't be handled. Or maybe it will. But later.
typedef struct FileSystemData_t_{
	/// To check the partition has the correct formatting.
	char partitionFormat[PARTITIONFORMATSTRINGLEN];
	/// To make sure incompatible versions are not handleled by the wrong program.
	uint16_t version;
	uint32_t blockCount;
	uint32_t blockSize;
	blockid_t fsRoot;
	// The bytemap uses the last 4 bytes to point to the next block.
	blockid_t bitmap;
}FileSystemData_t;

// Defined in filehandle.h
struct FileHandle_t_;

// The struct is the "global variable of the file system.
typedef struct FileSystemHandle_t_{
	FileSystemData_t fsd;
	HardDriveInterface_t* hdi;
	uint32_t nAllocatedFileHandles;
	struct FileHandle_t_* openedFilesHandles;
	// Later :
	// - Block cache
}FileSystemHandle_t;

// Format the given drive.
fs_ret_t fs_format(HardDriveInterface_t* hdi);

// Open a file system, and fill the handle allowing to access it.
// Only one handle at once can be created for a given file system.
fs_ret_t fs_openFileSystem(HardDriveInterface_t* hdi, FileSystemHandle_t *fsh);
// Close the file system handle.
fs_ret_t fs_closeFileSystem(FileSystemHandle_t *fsh);

// Change the position of the system root.
fs_ret_t fs_setFileSystemRootPos(FileSystemHandle_t *fsh, blockid_t pos);


// Tells if the given block is allocated by the file system.
fs_ret_t fs_getIsBlockOccuiped(FileSystemHandle_t *fsh,blockid_t blockToCheck);
// Set the given block to allocated.
fs_ret_t fs_setBlockToOccuiped(FileSystemHandle_t *fsh,blockid_t blockToSet);
// Set the given block to non-allocated.
fs_ret_t fs_freeBlock(FileSystemHandle_t *fsh,blockid_t blockToFree);

// Finds an empty block, set it to occuiped and place it in blockSelected.
// Returns 0 if a block was found.
fs_ret_t fs_bookAnyEmptyBlock(FileSystemHandle_t *fsh,blockid_t *blockSelected);

// sets blocksOccuipedCount to the total number of occuiped blocks.
fs_ret_t fs_diskUsage(FileSystemHandle_t *fsh, uint32_t *blocksOccuipedCount);

#endif // FILE_filesystemdata_H


